home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step05 / supfilesrv.c < prev   
Encoding:
Text File  |  1994-08-02  |  52.5 KB  |  1,860 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  *
  25. /*
  26.  * supfilesrv -- SUP File Server
  27.  *
  28.  * Usage:  supfilesrv [-l] [-P] [-N] [-R]
  29.  *    -l    "live" -- don't fork daemon
  30.  *    -P    "debug ports" -- use debugging network ports
  31.  *    -N    "debug network" -- print debugging messages for network i/o
  32.  *    -R    "RCS mode" -- if file is an rcs file, use co to get contents
  33.  *
  34.  **********************************************************************
  35.  * HISTORY
  36.  * 13-Sep-92  Mary Thompson (mrt) at Carnegie-Mellon University
  37.  *    Changed name of sup program in xpatch from /usr/cs/bin/sup to
  38.  *    /usr/bin/sup for exported version of sup.
  39.  *
  40.  * 7-July-93  Nate Williams at Montana State University
  41.  *    Modified SUP to use gzip based compression when sending files
  42.  *    across the network to save BandWidth
  43.  *
  44.  * $Log: supfilesrv.c,v $
  45.  * Revision 1.5  1993/08/04  17:46:21  brezak
  46.  * Changes from nate for gzip'ed sup
  47.  *
  48.  * Revision 1.3  1993/06/05  21:32:17  cgd
  49.  * use daemon() to put supfilesrv into daemon mode...
  50.  *
  51.  * Revision 1.2  1993/05/24  17:57:31  brezak
  52.  * Remove netcrypt.c. Remove unneeded files. Cleanup make.
  53.  *
  54.  * Revision 1.20  92/09/09  22:05:00  mrt
  55.  *     Added Brad's change to make sendfile take a va_list.
  56.  *     Added support in login to accept an non-encrypted login
  57.  *     message if no user or password is being sent. This supports
  58.  *     a non-crypting version of sup. Also fixed to skip leading
  59.  *     white space from crypts in host files.
  60.  *     [92/09/01            mrt]
  61.  * 
  62.  * Revision 1.19  92/08/11  12:07:59  mrt
  63.  *         Made maxchildren a patchable variable, which can be set by the
  64.  *         command line switch -C or else defaults to the MAXCHILDREN
  65.  *         defined in sup.h. Added most of Brad's STUMP changes.
  66.  *     Increased PGMVERSION to 12 to reflect substantial changes.
  67.  *     [92/07/28            mrt]
  68.  * 
  69.  * Revision 1.18  90/12/25  15:15:39  ern
  70.  *     Yet another rewrite of the logging code. Make up the text we will write
  71.  *        and then get in, write it and get out.
  72.  *     Also set error on write-to-full-disk if the logging is for recording
  73.  *        server is busy.
  74.  *     [90/12/25  15:15:15  ern]
  75.  * 
  76.  * Revision 1.17  90/05/07  09:31:13  dlc
  77.  *     Sigh, some more fixes to the new "crypt" file handling code.  First,
  78.  *     just because the "crypt" file is in a local file system does not mean
  79.  *     it can be trusted.  We have to check for hard links to root owned
  80.  *     files whose contents could be interpretted as a crypt key.  For
  81.  *     checking this fact, the new routine stat_info_ok() was added.  This
  82.  *     routine also makes other sanity checks, such as owner only permission,
  83.  *     the file is a regular file, etc.  Also, even if the uid/gid of th
  84.  *     "crypt" file is not going to be used, still use its contents in order
  85.  *     to cause fewer surprises to people supping out of a shared file system
  86.  *     such as AFS.
  87.  *     [90/05/07            dlc]
  88.  * 
  89.  * Revision 1.16  90/04/29  04:21:08  dlc
  90.  *     Fixed logic bug in docrypt() which would not get the stat information
  91.  *     from the crypt file if the crypt key had already been set from a
  92.  *     "host" file.
  93.  *     [90/04/29            dlc]
  94.  * 
  95.  * Revision 1.15  90/04/18  19:51:27  dlc
  96.  *     Added the new routines local_file(), link_nofollow() for use in
  97.  *     dectecting whether a file is located in a local file system.  These
  98.  *     routines probably should have been in another module, but only
  99.  *     supfilesrv needs to do the check and none of its other modules seemed
  100.  *     appropriate.  Note, the implementation should be changed once we have
  101.  *     direct kernel support, for example the fstatfs(2) system call, for
  102.  *     detecting the type of file system a file resides.  Also, I changed
  103.  *     the routines which read the crosspatch crypt file or collection crypt
  104.  *     file to save the uid and gid from the stat information obtained via
  105.  *     the local_file() call (when the file is local) at the same time the
  106.  *     crypt key is read.  This change disallows non-local files for the
  107.  *     crypt key to plug a security hole involving the usage of the uid/gid
  108.  *     of the crypt file to define who the the file server should run as.  If
  109.  *     the saved uid/gid are both valid, then the server will set its uid/gid
  110.  *     to these values.
  111.  *     [90/04/18            dlc]
  112.  * 
  113.  * Revision 1.14  89/08/23  14:56:15  gm0w
  114.  *     Changed msgf routines to msg routines.
  115.  *     [89/08/23            gm0w]
  116.  * 
  117.  * Revision 1.13  89/08/03  19:57:33  mja
  118.  *     Remove setaid() call.
  119.  * 
  120.  * Revision 1.12  89/08/03  19:49:24  mja
  121.  *     Updated to use v*printf() in place of _doprnt().
  122.  *     [89/04/19            mja]
  123.  * 
  124.  * 11-Sep-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  125.  *    Added code to record release name in logfile.
  126.  *
  127.  * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  128.  *    Added host=<hostfile> support to releases file. [V7.12]
  129.  *
  130.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  131.  *    Added crosspatch support.  Created docrypt() routine for crypt
  132.  *    test message.
  133.  *
  134.  * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  135.  *    Removed common information logging code, the quiet switch, and
  136.  *    moved samehost() check to after device/inode check.
  137.  *
  138.  * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  139.  *    Added code for "release" support. [V5.11]
  140.  *
  141.  * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
  142.  *    Added code to record final status of client in logfile. [V5.10]
  143.  *
  144.  * 22-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
  145.  *    Mergered divergent CS and ECE versions. [V5.9a]
  146.  *
  147.  * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  148.  *    Removed support for version 3 of SUP protocol.  Added changes
  149.  *    to make lint happy.  Added calls to new logging routines. [V5.9]
  150.  *
  151.  * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
  152.  *    Fixed so no password check is done when crypts are used.
  153.  *
  154.  * 25-Nov-86  Rudy Nedved (ern) at Carnegie-Mellon University
  155.  *    Set F_APPEND fcntl in logging to increase the chance
  156.  *    that the log entry from this incarnation of the file
  157.  *    server will not be lost by another incarnation. [V5.8]
  158.  *
  159.  * 20-Oct-86  Dan Nydick (dan) at Carnegie-Mellon University
  160.  *    Changed not to call okmumbles when not compiled with CMUCS.
  161.  *
  162.  * 04-Aug-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  163.  *    Added code to increment scmdebug as more -N flags are
  164.  *    added. [V5.7]
  165.  *
  166.  * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  167.  *    Renamed local variable in main program from "sigmask" to
  168.  *    "signalmask" to avoid name conflict with 4.3BSD identifier.
  169.  *    Conditionally compile in calls to CMU routines, "setaid" and
  170.  *    "logaccess". [V5.6]
  171.  *
  172.  * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  173.  *    Changed supfilesrv to use the crypt file owner and group for
  174.  *    access purposes, rather than the directory containing the crypt
  175.  *    file. [V5.5]
  176.  *
  177.  * 07-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  178.  *    Added code to keep logfiles in repository collection directory.
  179.  *    Added code for locking collections. [V5.4]
  180.  *
  181.  * 05-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  182.  *    Added code to support new FSETUPBUSY return.  Now accepts all
  183.  *    connections and tells any clients after the 8th that the
  184.  *    fileserver is busy.  New clients will retry again later. [V5.3]
  185.  *
  186.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  187.  *    Major rewrite for protocol version 4. [V4.2]
  188.  *
  189.  * 12-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  190.  *    Fixed close of crypt file to use file pointer as argument
  191.  *    instead of string pointer.
  192.  *
  193.  * 24-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  194.  *    Allow "!hostname" lines and comments in collection "host" file.
  195.  *
  196.  * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  197.  *    Don't use access() on symbolic links since they may not point to
  198.  *    an existing file.
  199.  *
  200.  * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  201.  *    Added code to restrict file server availability to when it has
  202.  *    less than or equal to eight children.
  203.  *
  204.  * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  205.  *    Merged 4.1 and 4.2 versions together.
  206.  *
  207.  * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  208.  *    Created for 4.2 BSD.
  209.  *
  210.  **********************************************************************
  211.  */
  212.  
  213. #include <libc.h>
  214. #ifdef AFS
  215. #include <afs/param.h>
  216. #undef MAXNAMLEN
  217. #endif
  218. #include <sys/param.h>
  219. #include <c.h>
  220. #include <signal.h>
  221. #include <errno.h>
  222. #include <setjmp.h>
  223. #include <pwd.h>
  224. #include <grp.h>
  225. #if __STDC__
  226. #include <stdarg.h>
  227. #else
  228. #include <varargs.h>
  229. #endif
  230. #include <sys/time.h>
  231. #include <sys/resource.h>
  232. #include <sys/wait.h>
  233. #include <sys/stat.h>
  234. #include <sys/file.h>
  235. #include <sys/dir.h>
  236. #if    MACH
  237. #include <sys/ioctl.h>
  238. #endif
  239. #if    CMUCS
  240. #include <acc.h>
  241. #include <sys/ttyloc.h>
  242. #include <access.h>
  243. #include <sys/viceioctl.h>
  244. #else    CMUCS
  245. #define ACCESS_CODE_OK        0
  246. #define ACCESS_CODE_BADPASSWORD (-2)
  247. #endif  CMUCS
  248. #include "sup.h"
  249. #define MSGFILE
  250. #include "supmsg.h"
  251.  
  252. #ifdef    lint
  253. /*VARARGS1*//*ARGSUSED*/
  254. static void quit(status) {};
  255. #endif    /* lint */
  256.  
  257. #if __STDC__
  258. void goaway (char *,...);
  259. #endif
  260.  
  261. extern int errno;
  262. long time ();
  263. uid_t getuid ();
  264.  
  265. int maxchildren;
  266.  
  267. /*
  268.  * These are used to save the stat information from the crosspatch crypt
  269.  * file or collection crypt file at the time it is opened for the crypt
  270.  * key and it is verified to be a local file.
  271.  */
  272. int runas_uid = -1;
  273. int runas_gid = -1;
  274.  
  275. #define PGMVERSION 13
  276.  
  277. /*************************
  278.  ***    M A C R O S    ***
  279.  *************************/
  280.  
  281. #define HASHBITS 8
  282. #define HASHSIZE (1<<HASHBITS)
  283. #define HASHMASK (HASHSIZE-1)
  284. #define HASHFUNC(x,y) ((x)&HASHMASK)
  285.  
  286. /*******************************************
  287.  ***    D A T A   S T R U C T U R E S    ***
  288.  *******************************************/
  289.  
  290. struct hashstruct {            /* hash table for number lists */
  291.     int Hnum1;            /* numeric keys */
  292.     int Hnum2;
  293.     char *Hname;            /* string value */
  294.     TREE *Htree;            /* TREE value */
  295.     struct hashstruct *Hnext;
  296. };
  297. typedef struct hashstruct HASH;
  298.  
  299. /*********************************************
  300.  ***    G L O B A L   V A R I A B L E S    ***
  301.  *********************************************/
  302.  
  303. char program[] = "supfilesrv";        /* program name for SCM messages */
  304. int progpid = -1;            /* and process id */
  305.  
  306. jmp_buf sjbuf;                /* jump location for network errors */
  307. TREELIST *listTL;            /* list of trees to upgrade */
  308.  
  309. int live;                /* -l flag */
  310. int dbgportsq;                /* -P flag */
  311. extern int scmdebug;            /* -N flag */
  312. extern int netfile;
  313. #ifdef RCS
  314. int candorcs;                /* -R flag */
  315. int dorcs = FALSE;
  316. #endif
  317.  
  318. char *clienthost;            /* host name of client */
  319. int nchildren;                /* number of children that exist */
  320. char *prefix;                /* collection pathname prefix */
  321. char *release;                /* collection release name */
  322. char *cryptkey;                /* encryption key if non-null */
  323. #ifdef CVS
  324. char *cvs_root;                /* RCS root */
  325. #endif
  326. char *rcs_branch;            /* RCS branch name */
  327. int lockfd;                /* descriptor of lock file */
  328.  
  329. /* global variables for scan functions */
  330. int trace = FALSE;            /* directory scan trace */
  331. int cancompress = FALSE;        /* Can we compress files */
  332. int docompress = FALSE;            /* Do we compress files */
  333.  
  334. HASH *uidH[HASHSIZE];            /* for uid and gid lookup */
  335. HASH *gidH[HASHSIZE];
  336. HASH *inodeH[HASHSIZE];            /* for inode lookup for linked file check */
  337.  
  338. char *fmttime ();            /* time format routine */
  339.  
  340. /*************************************
  341.  ***    M A I N   R O U T I N E    ***
  342.  *************************************/
  343.  
  344. main (argc,argv)
  345. int argc;
  346. char **argv;
  347. {
  348. #ifdef _ABI_SOURCE
  349.     register int x,pid;
  350.     sigset_t signalmask, oldsignalmask;
  351.     struct sigaction chldvec,ignvec,oldvec;
  352. #else
  353.     register int x,pid,signalmask;
  354.     struct sigvec chldvec,ignvec,oldvec;
  355. #endif
  356.     int chldsig ();
  357.     long tloc;
  358.  
  359.     /* initialize global variables */
  360.     pgmversion = PGMVERSION;    /* export version number */
  361.     server = TRUE;            /* export that we're not a server */
  362.     collname = NULL;        /* no current collection yet */
  363.     maxchildren = MAXCHILDREN;    /* defined in sup.h */
  364.  
  365.     init (argc,argv);        /* process arguments */
  366.  
  367. #ifdef HAS_DAEMON
  368.     if (!live)            /* if not debugging, turn into daemon */
  369.         daemon(0, 0);
  370. #endif
  371.  
  372.     logopen ("supfile");
  373.     tloc = time ((long *)NULL);
  374.     loginfo ("SUP File Server Version %d.%d (%s) starting at %s",
  375.         PROTOVERSION,PGMVERSION,scmversion,fmttime (tloc));
  376.     if (live) {
  377.         x = service ();
  378.         if (x != SCMOK)
  379.             logquit (1,"Can't connect to network");
  380.         answer ();
  381.         (void) serviceend ();
  382.         exit (0);
  383.     }
  384. #ifdef _ABI_SOURCE
  385.     ignvec.sa_handler = SIG_IGN;
  386.     sigemptyset (&(ignvec.sa_mask));
  387.     ignvec.sa_flags = 0;
  388.     (void) sigaction (SIGHUP,&ignvec,&oldvec);
  389.     (void) sigaction (SIGINT,&ignvec,&oldvec);
  390.     (void) sigaction (SIGPIPE,&ignvec,&oldvec);
  391.     chldvec.sa_handler = chldsig;
  392.     sigemptyset (&(chldvec.sa_mask));
  393.     chldvec.sa_flags = 0;
  394.     (void) sigaction (SIGCHLD,&chldvec,&oldvec);
  395. #else
  396.     ignvec.sv_handler = SIG_IGN;
  397.     ignvec.sv_onstack = 0;
  398.     ignvec.sv_mask = 0;
  399.     (void) sigvec (SIGHUP,&ignvec,&oldvec);
  400.     (void) sigvec (SIGINT,&ignvec,&oldvec);
  401.     (void) sigvec (SIGPIPE,&ignvec,&oldvec);
  402.     chldvec.sv_handler = chldsig;
  403.     chldvec.sv_mask = 0;
  404.     chldvec.sv_onstack = 0;
  405.     (void) sigvec (SIGCHLD,&chldvec,&oldvec);
  406. #endif
  407.     nchildren = 0;
  408.     for (;;) {
  409.         x = service ();
  410.         if (x != SCMOK) {
  411.             logerr ("Error in establishing network connection");
  412.             (void) servicekill ();
  413.             continue;
  414.         }
  415. #ifdef _ABI_SOURCE
  416.         sigemptyset (&signalmask);
  417.         sigaddset (&signalmask, SIGCHLD);
  418.         (void) sigprocmask (SIG_BLOCK, &signalmask, &oldsignalmask);
  419. #else
  420.         signalmask = sigblock(sigmask(SIGCHLD));
  421. #endif
  422.         if ((pid = fork()) == 0) { /* server process */
  423.             (void) serviceprep ();
  424.             answer ();
  425.             (void) serviceend ();
  426.             exit (0);
  427.         }
  428.         (void) servicekill ();    /* parent */
  429.         if (pid > 0) nchildren++;
  430. #ifdef _ABI_SOURCE
  431.         (void) sigprocmask (SIG_SETMASK, &oldsignalmask, NULL);
  432. #else
  433.         (void) sigsetmask(signalmask);
  434. #endif
  435.     }
  436. }
  437.  
  438. /*
  439.  * Child status signal handler
  440.  */
  441.  
  442. chldsig()
  443. {
  444.     union wait w;
  445.  
  446.     while (wait3(&w, WNOHANG, (struct rusage *)0) > 0) {
  447.         if (nchildren) nchildren--;
  448.     }
  449. }
  450.  
  451. /*****************************************
  452.  ***    I N I T I A L I Z A T I O N    ***
  453.  *****************************************/
  454.  
  455. usage ()
  456. {
  457.     quit (1,"Usage: supfilesrv [ -l | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
  458. }
  459.  
  460. init (argc,argv)
  461. int argc;
  462. char **argv;
  463. {
  464.     register int i;
  465.     register int x;
  466.     char *clienthost,*clientuser;
  467.     char *p,*q;
  468.     char buf[STRINGLENGTH];
  469.     int maxsleep;
  470.     register FILE *f;
  471.  
  472. #ifdef RCS
  473.         candorcs = FALSE;
  474. #endif
  475.     live = FALSE;
  476.     dbgportsq = FALSE;
  477.     scmdebug = 0;
  478.     clienthost = NULL;
  479.     clientuser = NULL;
  480.     maxsleep = 5;
  481.     if (--argc < 0)
  482.         usage ();
  483.     argv++;
  484.     while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
  485.         switch (argv[0][1]) {
  486.         case 'l':
  487.             live = TRUE;
  488.             break;
  489.         case 'P':
  490.             dbgportsq = TRUE;
  491.             break;
  492.         case 'N':
  493.             scmdebug++;
  494.             break;
  495.         case 'C':
  496.             if (--argc < 1)
  497.                 quit (1,"Missing arg to -C\n");
  498.             argv++;
  499.             maxchildren = atoi(argv[0]);
  500.             break;
  501.         case 'H':
  502.             if (--argc < 3)
  503.                 quit (1,"Missing args to -H\n");
  504.             argv++;
  505.             clienthost = argv[0];
  506.             clientuser = argv[1];
  507.             cryptkey = argv[2];
  508.             argc -= 2;
  509.             argv += 2;
  510.             break;
  511. #ifdef RCS
  512.                 case 'R':
  513.                         candorcs = TRUE;
  514.                         break;
  515. #endif
  516.         default:
  517.             fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
  518.             break;
  519.         }
  520.         --argc;
  521.         argv++;
  522.     }
  523.     if (clienthost == NULL) {
  524.         if (argc != 0)
  525.             usage ();
  526.         x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
  527.         if (x != SCMOK)
  528.             quit (1,"Error in network setup");
  529.         for (i = 0; i < HASHSIZE; i++)
  530.             uidH[i] = gidH[i] = inodeH[i] = NULL;
  531.         return;
  532.     }
  533.     server = FALSE;
  534.     if (argc < 1)
  535.         usage ();
  536.     f = fopen (cryptkey,"r");
  537.     if (f == NULL)
  538.         quit (1,"Unable to open cryptfile %s\n",cryptkey);
  539.     if (p = fgets (buf,STRINGLENGTH,f)) {
  540.         if (q = index (p,'\n'))  *q = '\0';
  541.         if (*p == '\0')
  542.             quit (1,"No cryptkey found in %s\n",cryptkey);
  543.         cryptkey = salloc (buf);
  544.     }
  545.     (void) fclose (f);
  546.     x = request (dbgportsq ? DEBUGFPORT : FILEPORT,clienthost,&maxsleep);
  547.     if (x != SCMOK)
  548.         quit (1,"Unable to connect to host %s\n",clienthost);
  549.     x = msgsignon ();
  550.     if (x != SCMOK)
  551.         quit (1,"Error sending signon request to fileserver\n");
  552.     x = msgsignonack ();
  553.     if (x != SCMOK)
  554.         quit (1,"Error reading signon reply from fileserver\n");
  555.     printf ("SUP Fileserver %d.%d (%s) %d on %s\n",
  556.         protver,pgmver,scmver,fspid,remotehost());
  557.     free (scmver);
  558.     scmver = NULL;
  559.     if (protver < 7)
  560.         quit (1,"Remote fileserver does not implement reverse sup\n");
  561.     xpatch = TRUE;
  562.     xuser = clientuser;
  563.     x = msgsetup ();
  564.     if (x != SCMOK)
  565.         quit (1,"Error sending setup request to fileserver\n");
  566.     x = msgsetupack ();
  567.     if (x != SCMOK)
  568.         quit (1,"Error reading setup reply from fileserver\n");
  569.     switch (setupack) {
  570.     case FSETUPOK:
  571.         break;
  572.     case FSETUPSAME:
  573.         quit (1,"User %s not found on remote client\n",xuser);
  574.     case FSETUPHOST:
  575.         quit (1,"This host has no permission to reverse sup\n");
  576.     default:
  577.         quit (1,"Unrecognized file server setup status %d\n",setupack);
  578.     }
  579.     if (netcrypt (cryptkey) != SCMOK )
  580.         quit (1,"Running non-crypting fileserver\n");
  581.     crypttest = CRYPTTEST;
  582.     x = msgcrypt ();
  583.     if (x != SCMOK)
  584.         quit (1,"Error sending encryption test request\n");
  585.     x = msgcryptok ();
  586.     if (x == SCMEOF)
  587.         quit (1,"Data encryption test failed\n");
  588.     if (x != SCMOK)
  589.         quit (1,"Error reading encryption test reply\n");
  590.     logcrypt = CRYPTTEST;
  591.     loguser = NULL;
  592.     logpswd = NULL;
  593.     if (netcrypt (PSWDCRYPT) != SCMOK)    /* encrypt password data */
  594.         quit (1,"Running non-crypting fileserver\n");
  595.     x = msglogin ();
  596.     (void) netcrypt ((char *)NULL);    /* turn off encryption */
  597.     if (x != SCMOK)
  598.         quit (1,"Error sending login request to file server\n");
  599.     x = msglogack ();
  600.     if (x != SCMOK)
  601.         quit (1,"Error reading login reply from file server\n");
  602.     if (logack == FLOGNG)
  603.         quit (1,"%s\nImproper login to %s account\n",logerror,xuser);
  604.     xargc = argc;
  605.     xargv = argv;
  606.     x = msgxpatch ();
  607.     if (x != SCMOK)
  608.         quit (1,"Error sending crosspatch request\n");
  609.         crosspatch ();
  610.     exit (0);
  611. }
  612.  
  613. /*****************************************
  614.  ***    A N S W E R   R E Q U E S T    ***
  615.  *****************************************/
  616.  
  617. answer ()
  618. {
  619.     long starttime;
  620.     register int x;
  621.  
  622.     progpid = fspid = getpid ();
  623.     collname = NULL;
  624.     basedir = NULL;
  625.     prefix = NULL;
  626.     release = NULL;
  627.         rcs_branch = NULL;
  628. #ifdef CVS
  629.         cvs_root = NULL;
  630. #endif
  631.     goawayreason = NULL;
  632.     donereason = NULL;
  633.     lockfd = -1;
  634.     starttime = time ((long *)NULL);
  635.     if (!setjmp (sjbuf)) {
  636.         signon ();
  637.         setup ();
  638.         docrypt ();
  639.         login ();
  640.         if (xpatch) {
  641.             int fd;
  642.  
  643.             x = msgxpatch ();
  644.             if (x != SCMOK)
  645.                 exit (0);
  646.             xargv[0] = "sup";
  647.             xargv[1] = "-X";
  648.             xargv[xargc] = (char *)NULL;
  649.             (void) dup2 (netfile,0);
  650.             (void) dup2 (netfile,1);
  651.             (void) dup2 (netfile,2);
  652.             fd = getdtablesize ();
  653.             while (--fd > 2)
  654.                 (void) close (fd);
  655.             execvp (xargv[0],xargv);
  656.             exit (0);
  657.         }
  658.         listfiles ();
  659.         sendfiles ();
  660.     }
  661.     finishup (starttime);
  662.     if (collname)  free (collname);
  663.     if (basedir)  free (basedir);
  664.     if (prefix)  free (prefix);
  665.     if (release)  free (release);
  666.     if (rcs_branch)  free (rcs_branch);
  667. #ifdef CVS
  668.     if (cvs_root)  free (cvs_root);
  669. #endif
  670.     if (goawayreason) {
  671.         if (donereason == goawayreason)
  672.             donereason = NULL;
  673.         free (goawayreason);
  674.     }
  675.     if (donereason)  free (donereason);
  676.     if (lockfd >= 0)  (void) close (lockfd);
  677.     endpwent ();
  678.     (void) endgrent ();
  679. #if    CMUCS
  680.     endacent ();
  681. #endif    /* CMUCS */
  682.     Hfree (uidH);
  683.     Hfree (gidH);
  684.     Hfree (inodeH);
  685. }
  686.  
  687. /*****************************************
  688.  ***    S I G N   O N   C L I E N T    ***
  689.  *****************************************/
  690.  
  691. signon ()
  692. {
  693.     register int x;
  694.  
  695.     xpatch = FALSE;
  696.     x = msgsignon ();
  697.     if (x != SCMOK)  goaway ("Error reading signon request from client");
  698.     x = msgsignonack ();
  699.     if (x != SCMOK)  goaway ("Error sending signon reply to client");
  700.     free (scmver);
  701.     scmver = NULL;
  702. }
  703.  
  704. /*****************************************************************
  705.  ***    E X C H A N G E   S E T U P   I N F O R M A T I O N    ***
  706.  *****************************************************************/
  707.  
  708. setup ()
  709. {
  710.     register int x;
  711.     char *p,*q;
  712.     char buf[STRINGLENGTH];
  713.     register FILE *f;
  714.     struct stat sbuf;
  715.     register TREELIST *tl;
  716.  
  717.     if (protver > 7) {
  718.         cancompress = TRUE;
  719.     }
  720.     x = msgsetup ();
  721.     if (x != SCMOK)  goaway ("Error reading setup request from client");
  722.     if (protver < 4) {
  723.         setupack = FSETUPOLD;
  724.         (void) msgsetupack ();
  725.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  726.         goaway ("Sup client using obsolete version of protocol");
  727.     }
  728.     if (xpatch) {
  729.         register struct passwd *pw;
  730.         extern int link_nofollow(), local_file();
  731.  
  732.         if ((pw = getpwnam (xuser)) == NULL) {
  733.             setupack = FSETUPSAME;
  734.             (void) msgsetupack ();
  735.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  736.             goaway ("User not found");
  737.         }
  738.         (void) free (xuser);
  739.         xuser = salloc (pw->pw_dir);
  740.  
  741.         /* check crosspatch host access file */
  742.         cryptkey = NULL;
  743.         (void) sprintf (buf,FILEXPATCH,xuser);
  744.  
  745.         /* Turn off link following */
  746.         if (link_nofollow(1) != -1) {
  747.             int hostok = FALSE;
  748.             /* get stat info before open */
  749.             if (stat(buf, &sbuf) == -1)
  750.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  751.  
  752.             if ((f = fopen (buf,"r")) != NULL) {
  753.                 struct stat fsbuf;
  754.  
  755.                 while (p = fgets (buf,STRINGLENGTH,f)) {
  756.                     q = index (p,'\n');
  757.                     if (q)  *q = 0;
  758.                     if (index ("#;:",*p))  continue;
  759.                     q = nxtarg (&p," \t");
  760.                     if (*p == '\0')  continue;
  761.                     if (!matchhost(q)) continue;
  762.  
  763.                     cryptkey = salloc (p);
  764.                     hostok = TRUE;
  765.                     if (local_file(fileno(f), &fsbuf) > 0
  766.                         && stat_info_ok(&sbuf, &fsbuf)) {
  767.                         runas_uid = sbuf.st_uid;
  768.                         runas_gid = sbuf.st_gid;
  769.                     }
  770.                     break;
  771.                 }
  772.                 (void) fclose (f);
  773.             }
  774.  
  775.             /* Restore link following */
  776.             if (link_nofollow(0) == -1)
  777.                 goaway ("Restore link following");
  778.  
  779.             if (!hostok) {
  780.                 setupack = FSETUPHOST;
  781.                 (void) msgsetupack ();
  782.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  783.                 goaway ("Host not on access list");
  784.             }
  785.         }
  786.         setupack = FSETUPOK;
  787.         x = msgsetupack ();
  788.         if (x != SCMOK)
  789.             goaway ("Error sending setup reply to client");
  790.         return;
  791.     }
  792. #ifdef RCS
  793.         if (candorcs && release != NULL &&
  794.             (strncmp(release, "RCS.", 4) == 0)) {
  795.                 rcs_branch = salloc(&release[4]);
  796.                 free(release);
  797.                 release = salloc("RCS");
  798.                 dorcs = TRUE;
  799.         }
  800. #endif
  801.     if (release == NULL)
  802.         release = salloc (DEFRELEASE);
  803.     if (basedir == NULL || *basedir == '\0') {
  804.         basedir = NULL;
  805.         (void) sprintf (buf,FILEDIRS,DEFDIR);
  806.         f = fopen (buf,"r");
  807.         if (f) {
  808.             while (p = fgets (buf,STRINGLENGTH,f)) {
  809.                 q = index (p,'\n');
  810.                 if (q)  *q = 0;
  811.                 if (index ("#;:",*p))  continue;
  812.                 q = nxtarg (&p," \t=");
  813.                 if (strcmp(q,collname) == 0) {
  814.                     basedir = skipover(p," \t=");
  815.                     basedir = salloc (basedir);
  816.                     break;
  817.                 }
  818.             }
  819.             (void) fclose (f);
  820.         }
  821.         if (basedir == NULL) {
  822.             (void) sprintf (buf,FILEBASEDEFAULT,collname);
  823.             basedir = salloc(buf);
  824.         }
  825.     }
  826.     if (chdir (basedir) < 0)
  827.         goaway ("Can't chdir to base directory %s",basedir);
  828.     (void) sprintf (buf,FILEPREFIX,collname);
  829.     f = fopen (buf,"r");
  830.     if (f) {
  831.         while (p = fgets (buf,STRINGLENGTH,f)) {
  832.             q = index (p,'\n');
  833.             if (q)  *q = 0;
  834.             if (index ("#;:",*p))  continue;
  835.             prefix = salloc(p);
  836.             if (chdir (prefix) < 0)
  837.                 goaway ("Can't chdir to %s from base directory %s",
  838.                     prefix,basedir);
  839.             break;
  840.         }
  841.         (void) fclose (f);
  842.     }
  843.     x = stat (".",&sbuf);
  844.     if (prefix)  (void) chdir (basedir);
  845.     if (x < 0)
  846.         goaway ("Can't stat base/prefix directory");
  847.     if (nchildren >= maxchildren) {
  848.         setupack = FSETUPBUSY;
  849.         (void) msgsetupack ();
  850.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  851.         goaway ("Sup client told to try again later");
  852.     }
  853.     if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
  854.         setupack = FSETUPSAME;
  855.         (void) msgsetupack ();
  856.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  857.         goaway ("Attempt to upgrade to same directory on same host");
  858.     }
  859.     /* obtain release information */
  860.     if (!getrelease (release)) {
  861.         setupack = FSETUPRELEASE;
  862.         (void) msgsetupack ();
  863.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  864.         goaway ("Invalid release information");
  865.     }
  866.     /* check host access file */
  867.     cryptkey = NULL;
  868.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  869.         char *h;
  870.         if ((h = tl->TLhost) == NULL)
  871.             h = FILEHOSTDEF;
  872.         (void) sprintf (buf,FILEHOST,collname,h);
  873.         f = fopen (buf,"r");
  874.         if (f) {
  875.             int hostok = FALSE;
  876.             while (p = fgets (buf,STRINGLENGTH,f)) {
  877.                 int not;
  878.                 q = index (p,'\n');
  879.                 if (q)  *q = 0;
  880.                 if (index ("#;:",*p))  continue;
  881.                 q = nxtarg (&p," \t");
  882.                 if ((not = (*q == '!')) && *++q == '\0')
  883.                     q = nxtarg (&p," \t");
  884.                 hostok = (not == (matchhost(q) == 0));
  885.                 if (hostok) {
  886.                     while ((*p == ' ') || (*p == '\t')) p++;
  887.                     if (*p)  cryptkey = salloc (p);
  888.                     break;
  889.                 }
  890.             }
  891.             (void) fclose (f);
  892.             if (!hostok) {
  893.                 setupack = FSETUPHOST;
  894.                 (void) msgsetupack ();
  895.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  896.                 goaway ("Host not on access list for %s",
  897.                     collname);
  898.             }
  899.         }
  900.     }
  901.     /* try to lock collection */
  902.     (void) sprintf (buf,FILELOCK,collname);
  903.     x = open (buf,O_RDONLY,0);
  904.     if (x >= 0) {
  905.         if (flock (x,(LOCK_SH|LOCK_NB)) < 0) {
  906.             (void) close (x);
  907.             if (errno != EWOULDBLOCK)
  908.                 goaway ("Can't lock collection %s",collname);
  909.             setupack = FSETUPBUSY;
  910.             (void) msgsetupack ();
  911.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  912.             goaway ("Sup client told to wait for lock");
  913.         }
  914.         lockfd = x;
  915.     }
  916.     setupack = FSETUPOK;
  917.     x = msgsetupack ();
  918.     if (x != SCMOK)  goaway ("Error sending setup reply to client");
  919. }
  920.  
  921. /** Test data encryption **/
  922. docrypt ()
  923. {
  924.     register int x;
  925.     char *p,*q;
  926.     char buf[STRINGLENGTH];
  927.     register FILE *f;
  928.     struct stat sbuf;
  929.     extern int  link_nofollow(), local_file();
  930.  
  931.     if (!xpatch) {
  932.         (void) sprintf (buf,FILECRYPT,collname);
  933.  
  934.         /* Turn off link following */
  935.         if (link_nofollow(1) != -1) {
  936.             /* get stat info before open */
  937.             if (stat(buf, &sbuf) == -1)
  938.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  939.  
  940.             if ((f = fopen (buf,"r")) != NULL) {
  941.                 struct stat fsbuf;
  942.  
  943.                 if (cryptkey == NULL &&
  944.                     (p = fgets (buf,STRINGLENGTH,f))) {
  945.                     if (q = index (p,'\n'))  *q = '\0';
  946.                     if (*p)  cryptkey = salloc (buf);
  947.                 }
  948.                 if (local_file(fileno(f), &fsbuf) > 0
  949.                     && stat_info_ok(&sbuf, &fsbuf)) {
  950.                     runas_uid = sbuf.st_uid;
  951.                     runas_gid = sbuf.st_gid;
  952.                 }
  953.                 (void) fclose (f);
  954.             }
  955.             /* Restore link following */
  956.             if (link_nofollow(0) == -1)
  957.                 goaway ("Restore link following");
  958.         }
  959.     }
  960.     if ( netcrypt (cryptkey) != SCMOK )
  961.         goaway ("Runing non-crypting supfilesrv");
  962.     x = msgcrypt ();
  963.     if (x != SCMOK)
  964.         goaway ("Error reading encryption test request from client");
  965.     (void) netcrypt ((char *)NULL);
  966.     if (strcmp(crypttest,CRYPTTEST) != 0)
  967.         goaway ("Client not encrypting data properly");
  968.     free (crypttest);
  969.     crypttest = NULL;
  970.     x = msgcryptok ();
  971.     if (x != SCMOK)
  972.         goaway ("Error sending encryption test reply to client");
  973. }
  974.  
  975. /***************************************************************
  976.  ***    C O N N E C T   T O   P R O P E R   A C C O U N T    ***
  977.  ***************************************************************/
  978.  
  979. login ()
  980. {
  981.     char *changeuid ();
  982.     register int x,fileuid,filegid;
  983.  
  984.     (void) netcrypt (PSWDCRYPT);    /* encrypt acct name and password */
  985.     x = msglogin ();
  986.     (void) netcrypt ((char *)NULL); /* turn off encryption */
  987.     if (x != SCMOK)  goaway ("Error reading login request from client");
  988.     if ( logcrypt ) {
  989.         if (strcmp(logcrypt,CRYPTTEST) != 0) {
  990.         logack = FLOGNG;
  991.         logerror = "Improper login encryption";
  992.         (void) msglogack ();
  993.         goaway ("Client not encrypting login information properly");
  994.         }
  995.         free (logcrypt);
  996.         logcrypt = NULL;
  997.     }
  998.     if (loguser == NULL) {
  999.         if (cryptkey) {
  1000.             if (runas_uid >= 0 && runas_gid >= 0) {
  1001.                 fileuid = runas_uid;
  1002.                 filegid = runas_gid;
  1003.                 loguser = NULL;
  1004.             } else
  1005.                 loguser = salloc (DEFUSER);
  1006.         } else
  1007.             loguser = salloc (DEFUSER);
  1008.     }
  1009.     if ((logerror = changeuid (loguser,logpswd,fileuid,filegid)) != NULL) {
  1010.         logack = FLOGNG;
  1011.         (void) msglogack ();
  1012.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  1013.         goaway ("Client denied login access");
  1014.     }
  1015.     if (loguser)  free (loguser);
  1016.     if (logpswd)  free (logpswd);
  1017.     logack = FLOGOK;
  1018.     x = msglogack ();
  1019.     if (x != SCMOK)  goaway ("Error sending login reply to client");
  1020.     if (!xpatch)  /* restore desired encryption */
  1021.         if (netcrypt (cryptkey) != SCMOK)
  1022.             goaway("Running non-crypting supfilesrv");
  1023.     free (cryptkey);
  1024.     cryptkey = NULL;
  1025. }
  1026.  
  1027. /*****************************************
  1028.  ***    M A K E   N A M E   L I S T    ***
  1029.  *****************************************/
  1030.  
  1031. listfiles ()
  1032. {
  1033.     int denyone();
  1034.     register int x;
  1035.  
  1036.     refuseT = NULL;
  1037.     x = msgrefuse ();
  1038.     if (x != SCMOK)  goaway ("Error reading refuse list from client");
  1039.     getscanlists ();
  1040.     Tfree (&refuseT);
  1041.     x = msglist ();
  1042.     if (x != SCMOK)  goaway ("Error sending file list to client");
  1043.     Tfree (&listT);
  1044.     listT = NULL;
  1045.     needT = NULL;
  1046.     x = msgneed ();
  1047.     if (x != SCMOK)
  1048.         goaway ("Error reading needed files list from client");
  1049.     denyT = NULL;
  1050.     (void) Tprocess (needT,denyone);
  1051.     Tfree (&needT);
  1052.     x = msgdeny ();
  1053.     if (x != SCMOK)  goaway ("Error sending denied files list to client");
  1054.     Tfree (&denyT);
  1055. }
  1056.  
  1057. denyone (t)
  1058. register TREE *t;
  1059. {
  1060.     register TREELIST *tl;
  1061.     register char *name = t->Tname;
  1062.     register int update = (t->Tflags&FUPDATE) != 0;
  1063.     struct stat sbuf;
  1064.     register TREE *tlink;
  1065.     TREE *linkcheck ();
  1066.     char slinkname[STRINGLENGTH];
  1067.     register int x;
  1068.  
  1069.     for (tl = listTL; tl != NULL; tl = tl->TLnext)
  1070.         if ((t = Tsearch (tl->TLtree,name)) != NULL)
  1071.             break;
  1072.     if (t == NULL) {
  1073.         (void) Tinsert (&denyT,name,FALSE);
  1074.         return (SCMOK);
  1075.     }
  1076.     cdprefix (tl->TLprefix);
  1077.     if ((t->Tmode&S_IFMT) == S_IFLNK)
  1078.         x = lstat(name,&sbuf);
  1079.     else
  1080.         x = stat(name,&sbuf);
  1081.     if (x < 0 || (sbuf.st_mode&S_IFMT) != (t->Tmode&S_IFMT)) {
  1082.         (void) Tinsert (&denyT,name,FALSE);
  1083.         return (SCMOK);
  1084.     }
  1085.     switch (t->Tmode&S_IFMT) {
  1086.     case S_IFLNK:
  1087.         if ((x = readlink (name,slinkname,STRINGLENGTH)) <= 0) {
  1088.             (void) Tinsert (&denyT,name,FALSE);
  1089.             return (SCMOK);
  1090.         }
  1091.         slinkname[x] = '\0';
  1092.         (void) Tinsert (&t->Tlink,slinkname,FALSE);
  1093.         break;
  1094.     case S_IFREG:
  1095.         if (sbuf.st_nlink > 1 &&
  1096.             (tlink = linkcheck (t,(int)sbuf.st_dev,(int)sbuf.st_ino)))
  1097.         {
  1098.             (void) Tinsert (&tlink->Tlink,name,FALSE);
  1099.             return (SCMOK);
  1100.         }
  1101.         if (update)  t->Tflags |= FUPDATE;
  1102.     case S_IFDIR:
  1103.         t->Tuid = sbuf.st_uid;
  1104.         t->Tgid = sbuf.st_gid;
  1105.         break;
  1106.     default:
  1107.         (void) Tinsert (&denyT,name,FALSE);
  1108.         return (SCMOK);
  1109.     }
  1110.     t->Tflags |= FNEEDED;
  1111.     return (SCMOK);
  1112. }
  1113.  
  1114. /*********************************
  1115.  ***    S E N D   F I L E S    ***
  1116.  *********************************/
  1117.  
  1118. sendfiles ()
  1119. {
  1120.     int sendone(),senddir(),sendfile();
  1121.     register TREELIST *tl;
  1122.     register int x;
  1123.  
  1124.     /* Does the protocol support compression */
  1125.     if (cancompress) {
  1126.         /* Check for compression on sending files */
  1127.         x = msgcompress();
  1128.         if ( x != SCMOK)
  1129.             goaway ("Error sending compression check to server");
  1130.     }
  1131.     /* send all files */
  1132.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1133.         cdprefix (tl->TLprefix);
  1134. #ifdef CVS
  1135.                 if (candorcs) {
  1136.                         cvs_root = getcwd(NULL, 256);
  1137.                         if (access("CVSROOT", F_OK) < 0)
  1138.                                 dorcs = FALSE;
  1139.                         else {
  1140.                                 loginfo("is a CVSROOT \"%s\"\n", cvs_root);
  1141.                                 dorcs = TRUE;
  1142.                         }
  1143.                 }
  1144. #endif
  1145.         (void) Tprocess (tl->TLtree,sendone);
  1146.     }
  1147.     /* send directories in reverse order */
  1148.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1149.         cdprefix (tl->TLprefix);
  1150.         (void) Trprocess (tl->TLtree,senddir);
  1151.     }
  1152.     x = msgsend ();
  1153.     if (x != SCMOK)
  1154.         goaway ("Error reading receive file request from client");
  1155.     upgradeT = NULL;
  1156.     x = msgrecv (sendfile,0);
  1157.     if (x != SCMOK)
  1158.         goaway ("Error sending file to client");
  1159. }
  1160.  
  1161. sendone (t)
  1162. TREE *t;
  1163. {
  1164.     register int x,fd;
  1165.     register int fdtmp;
  1166.     char sys_com[STRINGLENGTH], temp_file[STRINGLENGTH], rcs_file[STRINGLENGTH];
  1167.         union wait status;
  1168.     char *uconvert(),*gconvert();
  1169.     int sendfile ();
  1170.  
  1171.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1172.         return (SCMOK);
  1173.     if ((t->Tmode&S_IFMT) == S_IFDIR) /* send no directories this pass */
  1174.         return (SCMOK);
  1175.     x = msgsend ();
  1176.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1177.     upgradeT = t;            /* upgrade file pointer */
  1178.     fd = -1;            /* no open file */
  1179.     if ((t->Tmode&S_IFMT) == S_IFREG) {
  1180.         if (!listonly && (t->Tflags&FUPDATE) == 0) {
  1181. #ifdef RCS
  1182.                         if (dorcs) {
  1183.                                 char rcs_release[STRINGLENGTH];
  1184.  
  1185.                 tmpnam(rcs_file);
  1186.                                 if (strcmp(&t->Tname[strlen(t->Tname)-2], ",v") == 0) {
  1187.                                         t->Tname[strlen(t->Tname)-2] = '\0';
  1188.                                         if (rcs_branch != NULL)
  1189. #ifdef CVS
  1190.                                                 sprintf(rcs_release, "-r %s", rcs_branch);
  1191. #else
  1192.                                                 sprintf(rcs_release, "-r%s", rcs_branch);
  1193. #endif
  1194.                                         else
  1195.                                                 rcs_release[0] = '\0';
  1196. #ifdef CVS
  1197.                                         sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, t->Tname, rcs_file);
  1198. #else
  1199.                                         sprintf(sys_com, "co -q -p %s %s > %s 2> /dev/null\n", rcs_release, t->Tname, rcs_file);
  1200. #endif
  1201.                                         /*loginfo("using rcs mode \"%s\"\n", sys_com);*/
  1202.                                         status.w_status = system(sys_com);
  1203.                                         if (status.w_status < 0 || status.w_retcode) {
  1204.                                                 /* Just in case */
  1205.                                                 unlink(rcs_file);
  1206.                                                 if (status.w_status < 0) {
  1207.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1208.                                                         t->Tmode = 0;
  1209.                                                 }
  1210.                                                 else {
  1211.                                                         /*logerr("rcs command failed \"%s\" = %d\n",
  1212.                                                                sys_com, status.w_retcode);*/
  1213.                                                         t->Tflags |= FUPDATE;
  1214.                                                 }
  1215.                                         }
  1216.                                         else if (docompress) {
  1217.                                                 tmpnam(temp_file);
  1218.                                                 sprintf(sys_com, "gzip -c < %s > %s\n", rcs_file, temp_file);
  1219.                                                 if (system(sys_com) < 0) {
  1220.                                                         /* Just in case */
  1221.                                                         unlink(temp_file);
  1222.                                                         unlink(rcs_file);
  1223.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1224.                                                         t->Tmode = 0;
  1225.                                                 }
  1226.                                                 fd = open (temp_file,O_RDONLY,0);
  1227.                                         }
  1228.                                         else
  1229.                                                 fd = open (rcs_file,O_RDONLY,0);
  1230.                                 }
  1231.                         }
  1232. #endif
  1233.                         if (fd == -1) {
  1234.                                 if (docompress) {
  1235.                                         tmpnam(temp_file);
  1236.                                         sprintf(sys_com, "gzip -c < %s > %s\n", t->Tname, temp_file);
  1237.                                         if (system(sys_com) < 0) {
  1238.                                                 /* Just in case */
  1239.                                                 unlink(temp_file);
  1240.                                                 goaway ("We died trying to \"%s\"", sys_com);
  1241.                                                 t->Tmode = 0;
  1242.                                         }
  1243.                                         fd = open (temp_file,O_RDONLY,0);
  1244.                                 }
  1245.                                 else
  1246.                                         fd = open (t->Tname,O_RDONLY,0);
  1247.                         }
  1248.             if (fd < 0 && (t->Tflags&FUPDATE) == 0)  t->Tmode = 0;
  1249.         }
  1250.         if (t->Tmode) {
  1251.             t->Tuser = salloc (uconvert (t->Tuid));
  1252.             t->Tgroup = salloc (gconvert (t->Tgid));
  1253.         }
  1254.     }
  1255.     x = msgrecv (sendfile,fd);
  1256.     if (docompress)
  1257.         unlink(temp_file);
  1258. #ifdef RCS
  1259.     if (dorcs)
  1260.         unlink(rcs_file);
  1261. #endif
  1262.     if (x != SCMOK)  goaway ("Error sending file to client");
  1263.     return (SCMOK);
  1264. }
  1265.  
  1266. senddir (t)
  1267. TREE *t;
  1268. {
  1269.     register int x;
  1270.     char *uconvert(),*gconvert();
  1271.     int sendfile ();
  1272.  
  1273.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1274.         return (SCMOK);
  1275.     if ((t->Tmode&S_IFMT) != S_IFDIR) /* send only directories this pass */
  1276.         return (SCMOK);
  1277.     x = msgsend ();
  1278.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1279.     upgradeT = t;            /* upgrade file pointer */
  1280.     t->Tuser = salloc (uconvert (t->Tuid));
  1281.     t->Tgroup = salloc (gconvert (t->Tgid));
  1282.     x = msgrecv (sendfile,0);
  1283.     if (x != SCMOK)  goaway ("Error sending file to client");
  1284.     return (SCMOK);
  1285. }
  1286.  
  1287. sendfile (t,ap)
  1288. register TREE *t;
  1289. va_list ap;
  1290. {
  1291.     register int x;
  1292.     int fd = va_arg(ap,int);
  1293.     if ((t->Tmode&S_IFMT) != S_IFREG || listonly || (t->Tflags&FUPDATE))
  1294.         return (SCMOK);
  1295.     x = writefile (fd);
  1296.     if (x != SCMOK)  goaway ("Error sending file to client");
  1297.         (void) close (fd);
  1298.     return (SCMOK);
  1299. }
  1300.  
  1301. /*****************************************
  1302.  ***    E N D   C O N N E C T I O N    ***
  1303.  *****************************************/
  1304.  
  1305. finishup (starttime)
  1306. long starttime;
  1307. {
  1308.     register int x = SCMOK;
  1309.     char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
  1310.     int logfd;
  1311.     struct stat sbuf;
  1312.     long finishtime;
  1313.     char *releasename;
  1314.  
  1315.     (void) netcrypt ((char *)NULL);
  1316.     if (protver < 6) {
  1317.         if (goawayreason != NULL)
  1318.             free (goawayreason);
  1319.         goawayreason = (char *)NULL;
  1320.         x = msggoaway();
  1321.         doneack = FDONESUCCESS;
  1322.         donereason = salloc ("Unknown");
  1323.     } else if (goawayreason == (char *)NULL)
  1324.         x = msgdone ();
  1325.     else {
  1326.         doneack = FDONEGOAWAY;
  1327.         donereason = goawayreason;
  1328.     }
  1329.     if (x == SCMEOF || x == SCMERR) {
  1330.         doneack = FDONEUSRERROR;
  1331.         donereason = salloc ("Premature EOF on network");
  1332.     } else if (x != SCMOK) {
  1333.         doneack = FDONESRVERROR;
  1334.         donereason = salloc ("Unknown SCM code");
  1335.     }
  1336.     if (doneack == FDONEDONTLOG)
  1337.         return;
  1338.     if (donereason == NULL)
  1339.         donereason = salloc ("No reason");
  1340.     if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
  1341.         logerr ("%s", donereason);
  1342.     else if (doneack == FDONEGOAWAY)
  1343.         logerr ("GOAWAY: %s",donereason);
  1344.     else if (doneack != FDONESUCCESS)
  1345.         logerr ("Reason %d:  %s",doneack,donereason);
  1346.     goawayreason = donereason;
  1347.     cdprefix ((char *)NULL);
  1348.     (void) sprintf (lognam,FILELOGFILE,collname);
  1349.     if ((logfd = open(lognam,O_APPEND|O_WRONLY,0644)) < 0)
  1350.         return; /* can not open file up...error */
  1351.     finishtime = time ((long *)NULL);
  1352.     p = tmpbuf;
  1353.     (void) sprintf (p,"%s ",fmttime (lasttime));
  1354.     p += strlen(p);
  1355.     (void) sprintf (p,"%s ",fmttime (starttime));
  1356.     p += strlen(p);
  1357.     (void) sprintf (p,"%s ",fmttime (finishtime));
  1358.     p += strlen(p);
  1359.     if ((releasename = release) == NULL)
  1360.         releasename = "UNKNOWN";
  1361.     (void) sprintf (p,"%s %s %d %s\n",remotehost(),releasename,
  1362.         FDONESUCCESS-doneack,donereason);
  1363.     p += strlen(p);
  1364. #if    MACH
  1365.     /* if we are busy dont get stuck updating the disk if full */
  1366.     if(setupack == FSETUPBUSY) {
  1367.         long l = FIOCNOSPC_ERROR;
  1368.         ioctl(logfd, FIOCNOSPC, &l);
  1369.     }
  1370. #endif    /* MACH */
  1371.     (void) write(logfd,tmpbuf,(p - tmpbuf));
  1372.     (void) close(logfd);
  1373. }
  1374.  
  1375. /***************************************************
  1376.  ***    H A S H   T A B L E   R O U T I N E S    ***
  1377.  ***************************************************/
  1378.  
  1379. Hfree (table)
  1380. HASH **table;
  1381. {
  1382.     register HASH *h;
  1383.     register int i;
  1384.     for (i = 0; i < HASHSIZE; i++)
  1385.         while (h = table[i]) {
  1386.             table[i] = h->Hnext;
  1387.             if (h->Hname)  free (h->Hname);
  1388.             free ((char *)h);
  1389.         }
  1390. }
  1391.  
  1392. HASH *Hlookup (table,num1,num2)
  1393. HASH **table;
  1394. int num1,num2;
  1395. {
  1396.     register HASH *h;
  1397.     register int hno;
  1398.     hno = HASHFUNC(num1,num2);
  1399.     for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
  1400.     return (h);
  1401. }
  1402.  
  1403. Hinsert (table,num1,num2,name,tree)
  1404. HASH **table;
  1405. int num1,num2;
  1406. char *name;
  1407. TREE *tree;
  1408. {
  1409.     register HASH *h;
  1410.     register int hno;
  1411.     hno = HASHFUNC(num1,num2);
  1412.     h = (HASH *) malloc (sizeof(HASH));
  1413.     h->Hnum1 = num1;
  1414.     h->Hnum2 = num2;
  1415.     h->Hname = name;
  1416.     h->Htree = tree;
  1417.     h->Hnext = table[hno];
  1418.     table[hno] = h;
  1419. }
  1420.  
  1421. /*********************************************
  1422.  ***    U T I L I T Y   R O U T I N E S    ***
  1423.  *********************************************/
  1424.  
  1425. TREE *linkcheck (t,d,i)
  1426. TREE *t;
  1427. int d,i;            /* inode # and device # */
  1428. {
  1429.     register HASH *h;
  1430.     h = Hlookup (inodeH,i,d);
  1431.     if (h)  return (h->Htree);
  1432.     Hinsert (inodeH,i,d,(char *)NULL,t);
  1433.     return ((TREE *)NULL);
  1434. }
  1435.  
  1436. char *uconvert (uid)
  1437. int uid;
  1438. {
  1439.     register struct passwd *pw;
  1440.     register char *p;
  1441.     register HASH *u;
  1442.     u = Hlookup (uidH,uid,0);
  1443.     if (u)  return (u->Hname);
  1444.     pw = getpwuid (uid);
  1445.     if (pw == NULL)  return ("");
  1446.     p = salloc (pw->pw_name);
  1447.     Hinsert (uidH,uid,0,p,(TREE*)NULL);
  1448.     return (p);
  1449. }
  1450.  
  1451. char *gconvert (gid)
  1452. int gid;
  1453. {
  1454.     register struct group *gr;
  1455.     register char *p;
  1456.     register HASH *g;
  1457.     g = Hlookup (gidH,gid,0);
  1458.     if (g)  return (g->Hname);
  1459.     gr = getgrgid (gid);
  1460.     if (gr == NULL)  return ("");
  1461.     p = salloc (gr->gr_name);
  1462.     Hinsert (gidH,gid,0,p,(TREE *)NULL);
  1463.     return (p);
  1464. }
  1465.  
  1466. char *changeuid (namep,passwordp,fileuid,filegid)
  1467. char *namep,*passwordp;
  1468. int fileuid,filegid;
  1469. {
  1470.     char *okpassword ();
  1471.     char *group,*account,*pswdp;
  1472.     struct passwd *pwd;
  1473.     struct group *grp;
  1474. #if    CMUCS
  1475.     struct account *acc;
  1476.     struct ttyloc tlc;
  1477. #endif    /* CMUCS */
  1478.     register int status = ACCESS_CODE_OK;
  1479.     char nbuf[STRINGLENGTH];
  1480.     static char errbuf[STRINGLENGTH];
  1481. #if    CMUCS
  1482.     int *grps;
  1483. #endif    /* CMUCS */
  1484.     char *p;
  1485.  
  1486.     if (namep == NULL) {
  1487.         pwd = getpwuid (fileuid);
  1488.         if (pwd == NULL) {
  1489.             (void) sprintf (errbuf,"Reason:  Unknown user id %d",
  1490.                 fileuid);
  1491.             return (errbuf);
  1492.         }
  1493.         grp = getgrgid (filegid);
  1494.         if (grp)  group = strcpy (nbuf,grp->gr_name);
  1495.         else  group = NULL;
  1496.         account = NULL;
  1497.         pswdp = NULL;
  1498.     } else {
  1499.         (void) strcpy (nbuf,namep);
  1500.         account = group = index (nbuf,',');
  1501.         if (group != NULL) {
  1502.             *group++ = '\0';
  1503.             account = index (group,',');
  1504.             if (account != NULL) {
  1505.                 *account++ = '\0';
  1506.                 if (*account == '\0')  account = NULL;
  1507.             }
  1508.             if (*group == '\0')  group = NULL;
  1509.         }
  1510.         pwd = getpwnam (nbuf);
  1511.         if (pwd == NULL) {
  1512.             (void) sprintf (errbuf,"Reason:  Unknown user %s",
  1513.                 nbuf);
  1514.             return (errbuf);
  1515.         }
  1516.         if (strcmp (nbuf,DEFUSER) == 0)
  1517.             pswdp = NULL;
  1518.         else
  1519.             pswdp = passwordp ? passwordp : "";
  1520. #ifdef AFS
  1521.                 if (strcmp (nbuf,DEFUSER) != 0) {
  1522.                         char *reason;
  1523.                         setpag(); /* set a pag */
  1524.                         if (ka_UserAuthenticate(pwd->pw_name, "", 0,
  1525.                                                 pswdp, 1, &reason)) {
  1526.                                 (void) sprintf (errbuf,"AFS authentication failed, %s",
  1527.                                                 reason);
  1528.                                 logerr ("Attempt by %s; %s",
  1529.                                         nbuf, errbuf);
  1530.                                 return (errbuf);
  1531.                         }
  1532.                 }
  1533. #endif
  1534.     }
  1535.     if (getuid () != 0) {
  1536.         if (getuid () == pwd->pw_uid)
  1537.             return (NULL);
  1538.         if (strcmp (pwd->pw_name,DEFUSER) == 0)
  1539.             return (NULL);
  1540.         logerr ("Fileserver not superuser");
  1541.         return ("Reason:  fileserver is not running privileged");
  1542.     }
  1543. #if    CMUCS
  1544.     tlc.tlc_hostid = TLC_UNKHOST;
  1545.     tlc.tlc_ttyid = TLC_UNKTTY;
  1546.     if (okaccess(pwd->pw_name,ACCESS_TYPE_SU,0,-1,tlc) != 1)
  1547.         status = ACCESS_CODE_DENIED;
  1548.     else {
  1549.         grp = NULL;
  1550.         acc = NULL;
  1551.         status = oklogin(pwd->pw_name,group,&account,pswdp,&pwd,&grp,&acc,&grps);
  1552.         if (status == ACCESS_CODE_OK) {
  1553.             if ((p = okpassword(pswdp,pwd->pw_name,pwd->pw_gecos)) != NULL)
  1554.                 status = ACCESS_CODE_INSECUREPWD;
  1555.         }
  1556.     }
  1557. #else    /* CMUCS */
  1558.     status = ACCESS_CODE_OK;
  1559.     if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
  1560.         if (strcmp(pwd->pw_passwd,(char *)crypt(pswdp,pwd->pw_passwd)))
  1561.             status = ACCESS_CODE_BADPASSWORD;
  1562. #endif    /* CMUCS */
  1563.     switch (status) {
  1564.     case ACCESS_CODE_OK:
  1565.         break;
  1566.     case ACCESS_CODE_BADPASSWORD:
  1567.         p = "Reason:  Invalid password";
  1568.         break;
  1569. #if    CMUCS
  1570.     case ACCESS_CODE_INSECUREPWD:
  1571.         (void) sprintf (errbuf,"Reason:  %s",p);
  1572.         p = errbuf;
  1573.         break;
  1574.     case ACCESS_CODE_DENIED:
  1575.         p = "Reason:  Access denied";
  1576.         break;
  1577.     case ACCESS_CODE_NOUSER:
  1578.         p = errbuf;
  1579.         break;
  1580.     case ACCESS_CODE_ACCEXPIRED:
  1581.         p = "Reason:  Account expired";
  1582.         break;
  1583.     case ACCESS_CODE_GRPEXPIRED:
  1584.         p = "Reason:  Group expired";
  1585.         break;
  1586.     case ACCESS_CODE_ACCNOTVALID:
  1587.         p = "Reason:  Invalid account";
  1588.         break;
  1589.     case ACCESS_CODE_MANYDEFACC:
  1590.         p = "Reason:  User has more than one default account";
  1591.         break;
  1592.     case ACCESS_CODE_NOACCFORGRP:
  1593.         p = "Reason:  No account for group";
  1594.         break;
  1595.     case ACCESS_CODE_NOGRPFORACC:
  1596.         p = "Reason:  No group for account";
  1597.         break;
  1598.     case ACCESS_CODE_NOGRPDEFACC:
  1599.         p = "Reason:  No group for default account";
  1600.         break;
  1601.     case ACCESS_CODE_NOTGRPMEMB:
  1602.         p = "Reason:  Not member of group";
  1603.         break;
  1604.     case ACCESS_CODE_NOTDEFMEMB:
  1605.         p = "Reason:  Not member of default group";
  1606.         break;
  1607.     case ACCESS_CODE_OOPS:
  1608.         p = "Reason:  Internal error";
  1609.         break;
  1610. #endif    /* CMUCS */
  1611.     default:
  1612.         (void) sprintf (p = errbuf,"Reason:  Status %d",status);
  1613.         break;
  1614.     }
  1615.     if (pwd == NULL)
  1616.         return (p);
  1617.     if (status != ACCESS_CODE_OK) {
  1618.         logerr ("Login failure for %s",pwd->pw_name);
  1619.         logerr ("%s",p);
  1620. #if    CMUCS
  1621.         logaccess (pwd->pw_name,ACCESS_TYPE_SUP,status,0,-1,tlc);
  1622. #endif    /* CMUCS */
  1623.         return (p);
  1624.     }
  1625. #if    CMUCS
  1626.     if (setgroups (grps[0], &grps[1]) < 0)
  1627.         logerr ("setgroups: %%m");
  1628.     if (setgid ((gid_t)grp->gr_gid) < 0)
  1629.         logerr ("setgid: %%m");
  1630.     if (setuid ((uid_t)pwd->pw_uid) < 0)
  1631.         logerr ("setuid: %%m");
  1632. #else   /* CMUCS */
  1633.     if (initgroups (pwd->pw_name,pwd->pw_gid) < 0)
  1634.         return("Error setting group list");
  1635.     if (setgid (pwd->pw_gid) < 0)
  1636.         logerr ("setgid: %%m");
  1637.     if (setuid (pwd->pw_uid) < 0)
  1638.         logerr ("setuid: %%m");
  1639. #endif    /* CMUCS */
  1640.     return (NULL);
  1641. }
  1642.  
  1643. #if __STDC__
  1644. void
  1645. goaway (char *fmt,...)
  1646. #else
  1647. /*VARARGS*//*ARGSUSED*/
  1648. goaway (va_alist)
  1649. va_dcl
  1650. #endif
  1651. {
  1652. #if !__STDC__
  1653.     register char *fmt;
  1654. #endif
  1655.     char buf[STRINGLENGTH];
  1656.     va_list ap;
  1657.  
  1658.     (void) netcrypt ((char *)NULL);
  1659. #if __STDC__
  1660.     va_start(ap,fmt);
  1661. #else
  1662.     va_start(ap);
  1663.     fmt = va_arg(ap,char *);
  1664. #endif
  1665.     vsnprintf(buf, sizeof(buf), fmt, ap);
  1666.     va_end(ap);
  1667.     goawayreason = salloc (buf);
  1668.     (void) msggoaway ();
  1669.     logerr ("%s",buf);
  1670.     longjmp (sjbuf,TRUE);
  1671. }
  1672.  
  1673. char *fmttime (time)
  1674. long time;
  1675. {
  1676.     static char buf[STRINGLENGTH];
  1677.     int len;
  1678.  
  1679.     (void) strcpy (buf,ctime (&time));
  1680.     len = strlen(buf+4)-6;
  1681.     (void) strncpy (buf,buf+4,len);
  1682.     buf[len] = '\0';
  1683.     return (buf);
  1684. }
  1685.  
  1686. /*
  1687.  * Determine whether the file referenced by the file descriptor 'handle' can
  1688.  * be trusted, namely is it a file resident in the local file system.
  1689.  *
  1690.  * The main method of operation is to perform operations on the file
  1691.  * descriptor so that an attempt to spoof the checks should fail, for
  1692.  * example renamimg the file from underneath us and/or changing where the
  1693.  * file lives from underneath us.
  1694.  *
  1695.  * returns: -1 for error, indicating that we can not tell
  1696.  *         0 for file is definately not local, or it is an RFS link
  1697.  *         1 for file is local and can be trusted
  1698.  *
  1699.  * Side effect: copies the stat information into the supplied buffer,
  1700.  * regardless of the type of file system the file resides.
  1701.  *
  1702.  * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
  1703.  * UFS, where the latter is considered a trusted file.  We assume that the
  1704.  * caller has disabled link following and will detect an attempt to access
  1705.  * a file through an RFS link, except in the case the the last component is
  1706.  * an RFS link.  With link following disabled, the last component itself is
  1707.  * interpreted as a regular file if it is really an RFS link, so we
  1708.  * disallow the RFS link identified by group "symlink" and mode "IEXEC by
  1709.  * owner only". An AFS file is
  1710.  * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
  1711.  * ioctls which operate on a file descriptor.  Note, this AFS ioctl is
  1712.  * implemented in the cache manager, so the decision does not involve a
  1713.  * query with the AFS file server.  An NFS file is detected by looking at
  1714.  * the major device number and seeing if it matches the known values for
  1715.  * MACH NSF/Sun OS 3.x or Sun OS 4.x.
  1716.  *
  1717.  * Having the fstatfs() system call would make this routine easier and
  1718.  * more reliable.
  1719.  *
  1720.  * Note, in order to make the checks simpler, the file referenced by the
  1721.  * file descriptor can not be a BSD style symlink.  Even with symlink
  1722.  * following of the last path component disabled, the attempt to open a
  1723.  * file which is a symlink will succeed, so we check for the BSD symlink
  1724.  * file type here.  Also, the link following on/off and RFS file types
  1725.  * are only relevant in a MACH environment. 
  1726.  */
  1727. #ifdef    AFS
  1728. #include <sys/viceioctl.h>
  1729. #endif
  1730.  
  1731. #define SYMLINK_GRP 64
  1732.  
  1733. int local_file(handle, sinfo)
  1734. int handle;
  1735. struct stat *sinfo;
  1736. {
  1737.     struct stat sb;
  1738. #ifdef    VIOCIGETCELL
  1739.     /*
  1740.      * dummies for the AFS ioctl
  1741.      */
  1742.     struct ViceIoctl vdata;
  1743.     char cellname[512];
  1744. #endif    /* VIOCIGETCELL */
  1745.  
  1746.     if (fstat(handle, &sb) < 0)
  1747.         return(-1);
  1748.     if (sinfo != NULL)
  1749.         *sinfo = sb;
  1750.  
  1751. #if    CMUCS
  1752.     /*
  1753.      * If the following test succeeds, then the file referenced by
  1754.      * 'handle' is actually an RFS link, so we will not trust it.
  1755.      * See <sys/inode.h>.
  1756.      */
  1757.     if (sb.st_gid == SYMLINK_GRP
  1758.         && (sb.st_mode & (S_IFMT|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
  1759.             == (S_IFREG|S_IEXEC))
  1760.         return(0);
  1761. #endif    /* CMUCS */
  1762.  
  1763.     /*
  1764.      * Do not trust BSD style symlinks either.
  1765.      */
  1766.     if ((sb.st_mode & S_IFMT) == S_IFLNK)
  1767.         return(0);
  1768.  
  1769. #ifdef    VIOCIGETCELL
  1770.     /*
  1771.      * This is the VIOCIGETCELL ioctl, which takes an fd, not
  1772.      * a path name.  If it succeeds, then the file is in AFS.
  1773.      *
  1774.      * On failure, ENOTTY indicates that the file was not in
  1775.      * AFS; all other errors are pessimistically assumed to be
  1776.      * a temporary AFS error.
  1777.      */
  1778.     vdata.in_size = 0;
  1779.     vdata.out_size = sizeof(cellname);
  1780.     vdata.out = cellname;
  1781.     if (ioctl(handle, VIOCIGETCELL, (char *)&vdata) != -1)
  1782.         return(0);
  1783.     if (errno != ENOTTY)
  1784.         return(-1);
  1785. #endif    /* VIOCIGETCELL */
  1786.  
  1787.     /*
  1788.      * Verify the file is not in NFS.
  1789.      *
  1790.      * Our current implementation and Sun OS 3.x use major device
  1791.      * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
  1792.      * determined this empirically -- DLC).  Without a fstatfs()
  1793.      * system call, this will have to do for now.
  1794.      */
  1795.     if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
  1796.         return(0);
  1797.  
  1798.     return(1);
  1799. }
  1800.  
  1801. /*
  1802.  * Companion routine for ensuring that a local file can be trusted.  Compare
  1803.  * various pieces of the stat information to make sure that the file can be
  1804.  * trusted.  Returns true for stat information which meets the criteria
  1805.  * for being trustworthy.  The main paranoia is to prevent a hard link to
  1806.  * a root owned file.  Since the link could be removed after the file is
  1807.  * opened, a simply fstat() can not be relied upon.  The two stat buffers
  1808.  * for comparison should come from a stat() on the file name and a following
  1809.  * fstat() on the open file.  Some of the following checks are also an
  1810.  * additional level of paranoia.  Also, this test will fail (correctly) if
  1811.  * either or both of the stat structures have all fields zeroed; typically
  1812.  * due to a stat() failure.
  1813.  */
  1814.  
  1815.  
  1816. int stat_info_ok(sb1, sb2)
  1817. struct stat *sb1, *sb2;
  1818. {
  1819.     return (sb1->st_ino == sb2->st_ino &&    /* Still the same file */
  1820.         sb1->st_dev == sb2->st_dev &&    /* On the same device */
  1821.         sb1->st_mode == sb2->st_mode &&     /* Perms (and type) same */
  1822.         (sb1->st_mode & S_IFMT) == S_IFREG && /* Only allow reg files */
  1823.         (sb1->st_mode & 077) == 0 &&    /* Owner only perms */
  1824.         sb1->st_nlink == sb2->st_nlink &&    /* # hard links same... */
  1825.         sb1->st_nlink == 1 &&        /* and only 1 */
  1826.         sb1->st_uid == sb2->st_uid &&    /* owner and ... */
  1827.         sb1->st_gid == sb2->st_gid &&    /* group unchanged */
  1828.         sb1->st_mtime == sb2->st_mtime &&    /* Unmodified between stats */
  1829.         sb1->st_ctime == sb2->st_ctime);    /* Inode unchanged.  Hopefully
  1830.                            a catch-all paranoid test */
  1831. }
  1832.  
  1833. #if MACH
  1834. /*
  1835.  * Twiddle symbolic/RFS link following on/off.  This is a no-op in a non
  1836.  * CMUCS/MACH environment.  Also, the setmodes/getmodes interface is used
  1837.  * mainly because it is simpler than using table(2) directly.
  1838.  */
  1839. #include <sys/table.h>
  1840.  
  1841. int link_nofollow(on)
  1842. int on;
  1843. {
  1844.     static int modes = -1;
  1845.  
  1846.     if (modes == -1 && (modes = getmodes()) == -1)
  1847.         return(-1);
  1848.     if (on)
  1849.         return(setmodes(modes | UMODE_NOFOLLOW));
  1850.     return(setmodes(modes));
  1851. }
  1852. #else    /* MACH */
  1853. /*ARGSUSED*/
  1854. int link_nofollow(on)
  1855. int on;
  1856. {
  1857.     return(0);
  1858. }
  1859. #endif    /* MACH */
  1860.